/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package network;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jmat.data.AbstractMatrix;
import org.jmat.data.Matrix;
import org.jmat.data.matrixDecompositions.EigenvalueDecomposition;
import weibo4j.model.WeiboException;

/**
 *
 * @author Administrator
 */
class communityData extends DataPreparation {

    Map<String, Integer> newID = new HashMap<String, Integer>();
    Map<Integer, String> oldID = new HashMap<Integer, String>();
    List<String> dangling = new ArrayList<String>();
    List<Double> pi = new ArrayList<Double>();
    List<Integer> Si = new ArrayList<Integer>();
    double alpha = 0.85;
    double G[][];
    double B[][];//B is described in newman's work. In this work, I combine newman's work and LinkRank.

    public void devide(List<List> community, int size) throws IOException {
        for (int i = 0; i < size; i++) {
            community.add(new ArrayList<Integer>());
        }
        for (int i = 0; i < size; i++) {
            List<Integer> c = community.get(i);
            int cSize = c.size();
            double[][] matrix = new double[cSize][cSize];
            for (int in = 0; in < cSize; in++) {
                int inNode = c.get(in);
                double deltaSum = 0;
                for (int k = 0; k < cSize; k++) {
                    int kNode = c.get(k);
                    deltaSum += 2 * B[inNode][kNode];
                }

                for (int out = 0; out < cSize; out++) {
                    int outNode = c.get(out);
                    matrix[in][out] = B[inNode][outNode] + B[outNode][inNode];
                }
            }
            if (matrix.length > 0) {

                AbstractMatrix Bmatrix = new Matrix(matrix);
                EigenvalueDecomposition eig = Bmatrix.eig();


                double max = 0;
                int index = 0;
                for (int m = 0; m < cSize; m++) {
                    double neweig = eig.getD().get(m, m);
                    if (neweig > max) {
                        max = neweig;
                        index = m;
                    }
                }
                int newc = size + i;
                List<Integer> removeList = new ArrayList<Integer>();
                //eig.getD().toCommandLine("Eigenvalue");
                //eig.getV().getColumn(index).toCommandLine("Eigenvector");
                for (int m = 0; m < cSize; m++) {
                    double v = eig.getV().get(m, index);
                    int SiPosition = c.get(m);
                    if (v > 0) {
                        Si.set(SiPosition, newc + 1);
                        community.get(newc).add(SiPosition);
                        removeList.add(SiPosition);
                    } else if (v == 0) {
                        double r = Math.random();
                        if (r > 0.5) {
                            Si.set(SiPosition, newc + 1);
                            community.get(newc).add(SiPosition);
                            removeList.add(SiPosition);
                        }
                    }
                }

                for (Integer s : removeList) {
                    community.get(i).remove(s);
                }
            }
        }

    }

    communityData() throws WeiboException, FileNotFoundException, IOException, InterruptedException, ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException{
        reKout();
        System.out.println("Kout ready.");
        reKin();
        System.out.println("Kin ready.");
        method2();
    }

    private void method1() {
        cG();
        System.out.println("G ready.");
        cPi();
        System.out.println("Pi ready.");
        cB();
        System.out.println("B ready.");
        cS();
        System.out.println("S ready.");
    }

    private void method2() {
        cB2();
        System.out.println("B ready.");
        cS2();
        System.out.println("S ready.");

    }

    private void cS2() {
        AbstractMatrix Bmatrix = new Matrix(B);
        Bmatrix = Bmatrix.plus(Bmatrix.transpose());
        EigenvalueDecomposition eig = Bmatrix.eig();
        int size = Bmatrix.getColumnDimension();

        double max = 0;
        int index = 0;
        for (int i = 0; i < size; i++) {
            double neweig = eig.getD().get(i, i);
            if (neweig > max) {
                max = neweig;
                index = i;
            }
        }

        for (int i = 0; i < size; i++) {
            double v = eig.getV().get(i, index);
            if (v > 0) {
                Si.add(1);
            } else if (v < 0) {
                Si.add(2);
            } else {
                double r = Math.random();
                if (r > 0.5) {
                    Si.add(1);
                } else {
                    Si.add(2);
                }
            }
        }
    }

    private void cS() {
        AbstractMatrix Bmatrix = new Matrix(B);
        EigenvalueDecomposition eig = Bmatrix.eig();
        int size = Bmatrix.getColumnDimension();

        double max = 0;
        int index = 0;
        for (int i = 0; i < size; i++) {
            double neweig = eig.getD().get(i, i);
            if (neweig > max) {
                max = neweig;
                index = i;
            }
        }
        for (int i = 0; i < size; i++) {
            double v = eig.getV().get(i, index);
            if (v > 0) {
                Si.add(1);
            } else if (v < 0) {
                Si.add(2);
            } else {
                double r = Math.random();
                if (r > 0.5) {
                    Si.add(1);
                } else {
                    Si.add(2);
                }
            }
        }
    }

    private void cB() {
        int size = G.length;
        B = new double[size][size];
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                B[i][j] = pi.get(i) * G[i][j] + pi.get(j) * G[j][i] - 2 * pi.get(i) * pi.get(j);
            }
        }
    }

    private void cPi() {
        AbstractMatrix Gmatrix = new Matrix(G);
        EigenvalueDecomposition eig = Gmatrix.transpose().eig();
        int size = Gmatrix.getColumnDimension();

        double max = 0;
        int index = 0;
        for (int i = 0; i < size; i++) {
            double neweig = eig.getD().get(i, i);
            if (neweig > max) {
                max = neweig;
                index = i;
            }
        }

        for (int i = 0; i < size; i++) {
            double v = eig.getV().get(i, index);
            pi.add(v);
        }
    }

    private void cB2() {
        int size = this.newID.size();
        int EdgeCount = 0;
        for (int i = 0; i < size; i++) {
            String keyi = oldID.get(i + 1);
            if (this.Kout.containsKey(keyi)) {
                EdgeCount += this.Kout.get(keyi);                
            }
        }
        B = new double[size][size];
        for (int i = 0; i < size; i++) {
            String keyi = oldID.get(i + 1);
            String ilinksto[] = {""};
            if (LinkOut.containsKey(keyi)) {
                ilinksto = this.LinkOut.get(keyi).split(" ");
            }
            List<String> ilinkstoList = new ArrayList<String>();
            ilinkstoList.addAll(Arrays.asList(ilinksto));

            int wiout = 0;
            int wiin = 0;
            if (this.Kout.containsKey(keyi)) {
                wiout = this.Kout.get(keyi);//wiout
            }
            if (this.Kin.containsKey(keyi)) {
                wiin = this.Kin.get(keyi);
            }

            for (int j = 0; j < size; j++) {
                int wij = 0;//wij
                String keyj = oldID.get(j + 1);
                if (ilinkstoList.contains(keyj)) {
                    wij = 1;
                }

                B[i][j] = (wij - wiin * wiout / EdgeCount);
            }
        }
    }

    private void cG() {
        int size = this.newID.size();
        int EdgeCount = 0;

        for (int i = 0; i < size; i++) {
            String keyi = oldID.get(i + 1);
            if (this.Kout.containsKey(keyi)) {
                EdgeCount += this.Kout.get(keyi);

            }
        }

        G = new double[size][size];
        for (int i = 0; i < size; i++) {
            String keyi = oldID.get(i + 1);
            String ilinksto[] = {""};
            if (LinkOut.containsKey(keyi)) {
                ilinksto = this.LinkOut.get(keyi).split(" ");
            }
            List<String> ilinkstoList = new ArrayList<String>();
            ilinkstoList.addAll(Arrays.asList(ilinksto));
            int a = 0;//ai
            int wiout = 0;
            if (this.Kout.containsKey(keyi)) {
                wiout = this.Kout.get(keyi);//wiout
            }
            if (dangling.contains(keyi)) {
                a = 1;
            }
            for (int j = 0; j < size; j++) {
                int wij = 0;//wij
                String keyj = oldID.get(j + 1);
                if (ilinkstoList.contains(keyj)) {
                    wij = 1;
                }
                if (wiout != 0) {
                    G[i][j] = alpha * wij / wiout + (1 - alpha + alpha * a) / size;
                } else {
                    G[i][j] = (1 - alpha + alpha * a) / size;
                }
            }
        }
    }

    private void reKout() {
        this.Kout.remove(Config.uid);
        this.Kout.remove("0");
        Set keys = this.Kout.keySet();
        int keycount = keys.size();
        for (int i = 0; i < keycount; i++) {
            String key = (String) keys.toArray()[i];
            int newkout = this.Kout.get(key) - 1;
            if (this.data.mBiFIDs.contains(key)) {
                newkout -= 1;
            }
            this.Kout.put(key, newkout);
            if (newkout == 0) {
                dangling.add(key);
            }
        }
    }

    private void reKin() {
        this.Kin.remove(Config.uid);
        this.Kin.remove("0");
        Set keys = this.Kin.keySet();
        Set keysKout = this.Kout.keySet();
        int keycount = keys.size();
        for (int i = 0; i < keycount; i++) {
            String key = (String) keys.toArray()[i];
            {
                int newkin = this.Kin.get(key) - 1;
                this.Kin.put(key, newkin);
                if (keysKout.contains(key)) {
                    this.newID.put(key, i + 1);
                    this.oldID.put(i + 1, key);
                }
            }
        }

    }
}
